---
title: 'Visual Testing in Cypress'
description: 'Learn how to use visual testing plugins in Cypress to ensure your application visually looks as intended.'
sidebar_label: 'Visual Testing'
---

<ProductHeading product="app" />

# Visual Testing in Cypress

:::info

##### <Icon name="question-circle" color="#4BBFD2" /> What you'll learn

- The difference between functional and visual testing
- How to use visual testing plugins
- Best practices for visual testing

:::

## Introduction

Cypress offers several solutions for testing an application including:

- [End-to-end testing](/app/end-to-end-testing/writing-your-first-end-to-end-test)
- [Component testing](/app/component-testing/get-started)
- [Accessibility testing](/app/guides/accessibility-testing)
- [UI Coverage](/ui-coverage/get-started/introduction)

While many of our solutions, like [Test Replay](/cloud/features/test-replay), [Cypress Accessibility](/accessibility/get-started/introduction)
and [UI Coverage](/ui-coverage/get-started/introduction), offer a visual display of the application, having an automated way to ensure your
application visually looks as intended is crucial. This is
where visual testing comes in.

Visual testing is a type of testing that focuses on the appearance of the application.
It is a way to ensure that the application looks the same to the user after changes are made.

:::visit-mount-example

```ts
it('completes todo', () => {
  -{cy.visit('/') // opens TodoMVC running at "baseUrl"::cy.mount(<Todos />)}-
  cy.get('.new-todo').type('write tests{enter}')
  cy.contains('.todo-list li', 'write tests').find('.toggle').check()

  cy.contains('.todo-list li', 'write tests').should('have.class', 'completed')
})
```

:::

You could technically write a functional test asserting the CSS properties using
the [`have.css` assertion](/app/references/assertions#CSS), but these may
quickly become cumbersome to write and maintain, especially when visual styles
rely on a lot of CSS styles.

```js
cy.get('.completed').should('have.css', 'text-decoration', 'line-through')
cy.get('.completed').should('have.css', 'color', 'rgb(217,217,217)')
```

Your visual styles may also rely on more than CSS, perhaps you want to ensure an
SVG or image has rendered correctly or shapes were correctly drawn to a canvas.

Luckily, Cypress gives a stable platform for
[including plugins](/app/plugins/plugins-guide) that _can perform visual
testing_.

Typically such plugins take an image snapshot of the entire application under
test or a specific element, and then compare the image to a previously approved
baseline image. If the images are the same (within a set pixel tolerance), it is
determined that the web application looks the same to the user. If there are
differences, then there has been some change to the DOM layout, fonts, colors or
other visual properties that needs to be investigated.

For example, one can use the
[cypress-plugin-snapshots](https://github.com/meinaart/cypress-plugin-snapshots)
plugin and catch the following visual regression:

```css
.todo-list li.completed label {
  color: #d9d9d9;
  /* removed the line-through */
}
```

```js
it('completes todo', () => {
  cy.visit('/')
  cy.get('.new-todo').type('write tests{enter}')
  cy.contains('.todo-list li', 'write tests').find('.toggle').check()

  cy.contains('.todo-list li', 'write tests').should('have.class', 'completed')

  // run 'npm install cypress-plugin-snapshots --save'
  // capture the element screenshot and
  // compare to the baseline image
  cy.get('.todoapp').toMatchImageSnapshot({
    imageConfig: {
      threshold: 0.001,
    },
  })
})
```

This open source plugin compares the baseline and the current images side by
side if pixel difference is above the threshold; notice how the baseline image
(_Expected result_) has the label text with the line through, while the new
image (_Actual result_) does not have it.

<DocsImage
  src="/img/app/visual-testing/diff.png"
  alt="Baseline vs current image"
/>

Like most image comparison tools, the plugin also shows a difference view on
mouse hover:

<DocsImage src="/img/app/visual-testing/diff-2.png" alt="Highlighted changes" />

## Tooling

There are several published, open source plugins, listed in the [Plugins](/app/plugins/plugins-list) Visual Testing section, and several
commercial companies have developed visual testing solutions on top of Cypress listed
below.

### Applitools

See [Applitools' official docs](https://applitools.com/cypress) and our [tutorial](https://applitools.com/tutorials/cypress.html).

<DocsVideo
  src="https://youtube.com/embed/qVRjhABuyG0"
  title="Creating a Flawless User Experience, End to End, Functional to Visual - Practical Hands-on Session"
/>

Second joint webinar with Applitools with a focus on
[Component Testing](/app/core-concepts/testing-types#What-is-Component-Testing)

<DocsVideo
  src="https://youtube.com/embed/Bxh_ebMk1aM"
  title="Visual Component Testing - (Applitools)"
/>

### Percy

See [Percy's official docs](https://docs.percy.io/docs/cypress) and our [tutorial](https://docs.percy.io/docs/cypress-tutorial).

:::info

The Cypress <Icon name="github" inline="true" contentType="rwa" /> uses the
`cy.percySnapshot()` command provided by the
[Cypress Percy plugin](https://github.com/percy/percy-cypress) to take visual
snapshots throughout the user journey end-to-end tests

Check out the
[Real World App test suites](https://github.com/cypress-io/cypress-realworld-app/tree/develop/cypress/tests/ui)
to see these Percy and Cypress in action.

:::

<DocsVideo
  src="https://youtube.com/embed/MXfZeE9RQDw"
  title="Cypress.io + Percy = End-to-end functional and visual testing for the web"
/>

### Happo

See [Happo's official docs](https://docs.happo.io/docs/cypress) and our [webinar](https://www.youtube.com/watch?v=C_p12IvN5HU) and [blog](https://www.cypress.io/blog/2020/05/27/webcast-recording-keep-your-ui-sharp/).

<DocsVideo
  src="https://youtube.com/embed/C_p12IvN5HU"
  title="Keep your UI Sharp: Ensuring Functional and Visual Quality with Cypress.io + Happo.io"
/>

### Chromatic

Chromatic leverages your existing Cypress setup—configuration, mocking, and tests—to enable visual testing of your application's UI.
With the Chromatic plugin installed, Chromatic captures an archive of your UI while your Cypress tests are running.

See [Chromatic's official docs](https://www.chromatic.com/docs/cypress/setup/?utm_source=cypress_docs) and their [blog](https://www.chromatic.com/blog/how-to-visual-test-with-cypress/?utm_source=cypress_docs).

### Argos

Argos integrates seamlessly with your existing Cypress setup—configuration, mocking, and tests—to enable visual testing of your application’s UI.
With Argos set up, it captures and analyzes screenshots during your Cypress test runs to detect visual changes.

Check out [Argos's official documentation](https://argos-ci.com/docs/quickstart/cypress) for setup instructions and best practices.

### Wopee.io

[Wopee.io](https://wopee.io) seamlessly integrates with Cypress to enhance test coverage, expedite maintenance, and ensure more resilient test runs. Aiming for autonomous visual testing, Wopee.io allows you to easily incorporate visual validation into your existing Cypress tests, adding an extra layer of quality assurance.

See [Wopee.io's official docs](https://docs.wopee.io/integrations/cypress/01-getting-started/?utm_source=cypress_docs), our [webinar](https://youtu.be/t008fYcBoi0) and their [blog](https://wopee.io/blog/autopilot-your-sw-testing/?utm_source=cypress_docs) and [webinar](https://youtu.be/t008fYcBoi0).

## Best practices

As a general rule there are some best practices when visual testing.

### Recognize the need for visual testing

<Icon name="exclamation-triangle" color="red" /> Assertions that verify style properties

```js
cy.get('.completed').should('have.css', 'text-decoration', 'line-through')
  .and('have.css', 'color', 'rgb(217,217,217)')
cy.get('.user-info').should('have.css', 'display', 'none')
...
```

If your end-to-end tests become full of assertions checking visibility, color
and other style properties, it might be time to start using visual diffing to
verify the page appearance.

### DOM state

:::tip

<Icon name="check-circle" color="green" /> **Best Practice:** Take a snapshot after
you confirm the page is done changing.

:::

For example, if the snapshot command is `cy.mySnapshotCommand`:

<Icon name="exclamation-triangle" color="red" /> **Incorrect Usage**

```js
// the web application takes time to add the new item,
// sometimes it takes the snapshot BEFORE the new item appears
cy.get('.new-todo').type('write tests{enter}')
cy.mySnapshotCommand()
```

<Icon name="check-circle" color="green" /> **Correct Usage**

```js
// use a functional assertion to ensure
// the web application has re-rendered the page
cy.get('.new-todo').type('write tests{enter}')
cy.contains('.todo-list li', 'write tests')
// great, the new item is displayed,
// now we can take the snapshot
cy.mySnapshotCommand()
```

### Timestamps

:::tip

<Icon name="check-circle" color="green" /> **Best Practice:** Control the timestamp
inside the application under test.

:::

Below we freeze the operating system's time to `Jan 1, 2018` using
[cy.clock()](/api/commands/clock) to ensure all images displaying dates and
times match.

```js
const now = new Date(2018, 1, 1)

cy.clock(now)
// ... test
cy.mySnapshotCommand()
```

### Application state

:::tip

<Icon name="check-circle" color="green" /> **Best Practice:** Use [cy.fixture()](/api/commands/fixture)
and network mocking to set the application state.

:::

Below we stub network calls using [cy.intercept()](/api/commands/intercept) to
return the same response data for each XHR request. This ensures that the data
displayed in our application images does not change.

```js
cy.intercept('/api/items', { fixture: 'items' }).as('getItems')
// ... action
cy.wait('@getItems')
cy.mySnapshotCommand()
```

### Visual diff elements

:::tip

<Icon name="check-circle" color="green" /> **Best Practice:** Use visual diffing
to check individual DOM elements rather than the entire page.

:::

Targeting specific DOM element will help avoid visual changes from component "X"
breaking tests in other unrelated components.

### Component testing

:::tip

<Icon name="check-circle" color="green" /> **Best Practice:** Use [Component Testing](/app/component-testing/get-started)
to test the individual components functionality in addition to end-to-end and visual
tests.

:::

## See also

- [After Screenshot API](/api/node-events/after-screenshot-api)
- [cy.screenshot()](/api/commands/screenshot)
- [Cypress.Screenshot](/api/cypress-api/screenshot-api)
- [Plugins](/app/plugins/plugins-guide)
- [Visual Testing Plugins](/app/plugins/plugins-list)
- [Node Events Overview](/api/node-events/overview)
- <Icon name="github" contentType="rwa" /> is a full stack example application that
  demonstrates **best practices and scalable strategies with Cypress in practical
  and realistic scenarios**.
- Read the blog post
  [Debug a Flaky Visual Regression Test](https://www.cypress.io/blog/2020/10/02/debug-a-flaky-visual-regression-test/)
